home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / KERNEL.C < prev    next >
Text File  |  1993-11-17  |  13KB  |  538 lines

  1. #undef    PROCLOG
  2.  
  3. /* Non pre-empting synchronization kernel, machine-independent portion */
  4. #if    defined(PROCLOG) || defined(PROCTRACE)
  5. #include <stdio.h>
  6. #endif
  7. #include <dos.h>
  8. #include <setjmp.h>
  9. #include "global.h"
  10. #include "mbuf.h"
  11. #include "proc.h"
  12. #include "timer.h"
  13. #include "socket.h"
  14. #include "daemon.h"
  15. #include "hardware.h"
  16. #ifdef PROCLOG
  17. #include "files.h"
  18. #endif
  19.  
  20. #ifdef PROCLOG
  21. FILE *proclog;
  22. #endif
  23.  
  24. struct proc *Curproc = NULLPROC;    /* Currently running process */
  25. struct proc *Rdytab = NULLPROC;        /* Processes ready to run (not including curproc) */
  26. struct proc *Waittab = NULLPROC;    /* Waiting process list */
  27. struct proc *Susptab = NULLPROC;    /* Suspended processes */
  28. static struct mbuf *Killq;
  29.  
  30. /*----------------------------------------------------------------------*
  31. * primitive semaphore operation to serialize resource access  (DK5DC)   *
  32. * semawait  waits for a semaphore to become free (0).                   *
  33. * If req is True, the semaphore will be incremented immediatly          *
  34. *                                                                       *
  35. * semrel will decrement the semaphore and set it to 0 if it becomes     *
  36. * negative                                                              *
  37. *-----------------------------------------------------------------------*/
  38.  
  39. void
  40. semwait(int *sema,int req)
  41. {
  42.    while(*sema > 0) {
  43.       pwait(sema);
  44.    }
  45.    if(req) {
  46.       *sema += 1;                       /* now lock it                  */
  47.    }
  48. }
  49.  
  50. void
  51. semrel(int *sema)
  52. {
  53.    if((*sema -= 1) <= 0) {
  54.       *sema = 0;
  55.    }
  56.    psignal(sema,0);                    /* signal to everbody who's waiting*/
  57.  
  58. }
  59.  
  60. /* Append proc entry to end of appropriate list */
  61. static void near
  62. addproc(struct proc *entry)            /* Pointer to entry */
  63. {
  64.     int i_state;
  65.     struct proc **head;
  66.  
  67.     if(entry == NULLPROC) {
  68.         return;
  69.     }
  70.     switch(entry->state){
  71.     case READY:
  72.         head = &Rdytab;
  73.         break;
  74.     case WAITING:
  75.         head = &Waittab;
  76.         break;
  77.     case SUSPEND:
  78.     case SUSPEND | WAITING:
  79.         head = &Susptab;
  80.         break;
  81.     }
  82.     i_state = dirps();
  83.  
  84.     entry->next = NULLPROC;
  85.  
  86.     if(*head == NULLPROC) {
  87.         /* Empty list, stick at beginning */
  88.         *head = entry;
  89.     } else {
  90.         struct proc *pp = *head;
  91.  
  92.         /* Find last entry on list */
  93.         for( ; pp->next != NULLPROC; pp = pp->next) ;
  94.         pp->next = entry;
  95.     }
  96.     restore(i_state);
  97. }
  98.  
  99. /* Remove a process entry from the appropriate table */
  100. static void near
  101. delproc(struct proc *entry)            /* Pointer to entry */
  102. {
  103.     int i_state;
  104.     struct proc *pp = NULLPROC, *pplast = NULLPROC, **head;
  105.  
  106.     if(entry == NULLPROC) {
  107.         return;
  108.     }
  109.     i_state = dirps();
  110.  
  111.     switch(entry->state) {
  112.     case READY:
  113.         head = &Rdytab;
  114.         break;
  115.     case WAITING:
  116.         head = &Waittab;
  117.         break;
  118.     case SUSPEND:
  119.     case SUSPEND|WAITING:
  120.         head = &Susptab;
  121.         break;
  122.     }
  123.     for(pp = *head; pp != NULLPROC; pplast = pp, pp = pp->next) {
  124.         if(pp == entry) {
  125.             if(pplast != NULLPROC) {
  126.                 pplast->next = pp->next;
  127.             } else {
  128.                 *head = pp->next;
  129.             }
  130.             break;
  131.         }
  132.     }
  133.     restore(i_state);
  134. }
  135.  
  136. /* Create a process descriptor for the main function. Must be actually
  137.  * called from the main function!
  138.  * Note that standard I/O is NOT set up here.
  139.  */
  140. struct proc *
  141. mainproc(char *name)
  142. {
  143.     /* Create process descriptor */
  144.     /* Don't call the xallocw functions! - DB3FL.920801 */
  145.     struct proc *pp = mxalloc(sizeof(struct proc));
  146.  
  147.     /* Create name */
  148.     sprintf(pp->name,"%.16s",name);
  149.  
  150.     pp->stksize = 0;
  151.  
  152.     /* Make current */
  153.     pp->state = READY;
  154.     Curproc = pp;
  155.  
  156. #ifdef PROCLOG
  157.     proclog = fopen("/proclog",APPEND_TEXT);
  158. #endif
  159.  
  160.     return pp;
  161. }
  162.  
  163. /* Create a new, ready process and return pointer to descriptor.
  164.  * The general registers are not initialized, but optional args are pushed
  165.  * on the stack so they can be seen by a C function.
  166.  */
  167. struct proc *
  168. newproc(
  169. char *name,                /* Arbitrary user-assigned name string */
  170. unsigned int stksize,    /* Stack size in words to allocate */
  171. void (*pc)(),            /* Initial execution address */
  172. int iarg,                /* Integer argument (argc) */
  173. void *parg1,            /* Generic pointer argument #1 (argv) */
  174. void *parg2,            /* Generic pointer argument #2 (session ptr) */
  175. int freeargs)            /* if set, free args list on termination */
  176. {
  177.     struct proc *pp;
  178.     int i;
  179.  
  180. #ifdef MDEBUG
  181.     chkstk();
  182. #endif
  183.     /* Create process descriptor */
  184.     pp = mxallocw(sizeof(struct proc));
  185.  
  186.     /* Allocate stack */
  187.     pp->stack = cxallocw(sizeof(int16),stksize);
  188.     pp->stksize = stksize;
  189.  
  190.     /* Create name */
  191.     sprintf(pp->name,"%.16s",name);
  192.  
  193.     /* Initialize stack for high-water check */
  194.     for(i = 0; i < pp->stksize; i++) {
  195.         pp->stack[i] = STACKPAT;
  196.     }
  197.     /* Do machine-dependent initialization of stack */
  198.     psetup(pp,iarg,parg1,parg2,pc);
  199.  
  200.     pp->freeargs = freeargs;
  201.     pp->iarg = iarg;
  202.     pp->parg1 = parg1;
  203.     pp->parg2 = parg2;
  204.  
  205.     /* Inherit creator's input and output sockets */
  206.     usesock(Curproc->input);
  207.     pp->input = Curproc->input;
  208.     usesock(Curproc->output);
  209.     pp->output = Curproc->output;
  210.  
  211.     /* Add to ready process table */
  212.     pp->state = READY;
  213.     addproc(pp);
  214.     return pp;
  215. }
  216.  
  217. /* Free resources allocated to specified process. If a process wants to kill
  218.  * itself, the reaper is called to do the dirty work. This avoids some
  219.  * messy situations that would otherwise occur, like freeing your own stack.
  220.  */
  221. void
  222. killproc(struct proc *pp)
  223. {
  224. #ifdef PROCLOG
  225.     extern int stkutil __ARGS((struct proc *pp));
  226. #endif
  227.  
  228.     if(pp == NULLPROC) {
  229.         return;
  230.     }
  231.     /* Don't check the stack here!
  232.      * Will cause infinite recursion if called from a stack error.
  233.      */
  234.     if(pp == Curproc) {
  235.         killself();    /* Doesn't return */
  236.     }
  237.     /* Close any open sockets */
  238.     freesock(pp);
  239.  
  240.     close_s(pp->input);
  241.     close_s(pp->output);
  242.  
  243.     /* Stop alarm clock in case it's running */
  244.     stop_timer(&pp->alarm);
  245.  
  246.     /* Alert everyone waiting for this proc to die */
  247.     psignal(pp,0);
  248.  
  249.     /* Remove from appropriate table */
  250.     delproc(pp);
  251.  
  252. #ifdef PROCLOG
  253.     if(!uploadstatus) {
  254.         fprintf(proclog,"size %5u max %5u name %s\n",
  255.             pp->stksize,stkutil(pp),pp->name);
  256.         fflush(proclog);
  257.     }
  258. #endif
  259.  
  260.     /* Free allocated memory resources */
  261.     if(pp->freeargs){
  262.         char **argv = pp->parg1;
  263.  
  264.         while(pp->iarg-- != 0) {
  265.             xfree(*argv++);
  266.         }
  267.         xfree(pp->parg1);
  268.     }
  269.     xfree(pp->stack);
  270.     xfree(pp);
  271. }
  272.  
  273. /* Terminate current process by sending a request to the killer process.
  274.  * Automatically called when a process function returns. Does not return.
  275.  */
  276. void
  277. killself(void)
  278. {
  279.     if(Curproc != NULLPROC) {
  280.         struct mbuf *bp = pushdown(NULLBUF,sizeof(Curproc));
  281.  
  282.         memcpy(bp->data,(char *)&Curproc,sizeof(Curproc));
  283.         enqueue(&Killq,bp);
  284.     }
  285.     /* "Wait for me; I will be merciful and quick." */
  286.     for(;;) {
  287.         pwait(NULL);
  288.     }
  289. }
  290.  
  291. /* Process used by processes that want to kill themselves */
  292. void
  293. killer(int i,void *v1,void *v2)
  294. {
  295.  
  296.     for(;;) {
  297.         struct proc *pp;
  298.         struct mbuf *bp;
  299.  
  300.         while(Killq == NULLBUF) {
  301.             pwait(&Killq);
  302.         }
  303.         bp = dequeue(&Killq);
  304.         pullup(&bp,(char *)&pp,sizeof(pp));
  305.         free_p(bp);
  306.  
  307.         if(pp != Curproc) {    /* We're immortal */
  308.             killproc(pp);
  309.         }
  310.     }
  311. }
  312.  
  313. /* Inhibit a process from running */
  314. void
  315. suspend(struct proc *pp)
  316. {
  317.     if(pp == NULLPROC) {
  318.         return;
  319.     }
  320.     if(pp != Curproc) {
  321.         delproc(pp);        /* Running process isn't on any list */
  322.     }
  323.     pp->state |= SUSPEND;
  324.  
  325.     if(pp != Curproc) {
  326.         addproc(pp);        /* pwait will do it for us */
  327.     } else {
  328.         pwait(NULL);
  329.     }
  330. }
  331.  
  332. /* Restart suspended process */
  333. void
  334. resume(struct proc *pp)
  335. {
  336.     if(pp == NULLPROC) {
  337.         return;
  338.     }
  339.     delproc(pp);            /* Can't be Curproc! */
  340.     pp->state &= ~SUSPEND;
  341.     addproc(pp);
  342. }
  343.  
  344. /* Wakeup waiting process, regardless of event it's waiting for. The process
  345.  * will see a return value of "val" from its pwait() call.
  346.  */
  347. void
  348. alert(struct proc *pp,void *val)
  349. {
  350.     if(pp == NULLPROC) {
  351.         return;
  352.     }
  353. #ifdef    XXX
  354.     if((pp->state & WAITING) == 0)
  355.         return;
  356. #endif
  357.  
  358. #ifdef    PROCTRACE
  359.     tprintf("alert(%lx,%u) [%s]\n",ptol(pp),val,pp->name);
  360. #endif
  361.  
  362.     if(pp != Curproc) {
  363.         delproc(pp);
  364.     }
  365.     pp->state &= ~WAITING;
  366.     pp->retval = val;
  367.     pp->event = 0;
  368.  
  369.     if(pp != Curproc) {
  370.         addproc(pp);
  371.     }
  372. }
  373.  
  374. /* Post a wait on a specified event and give up the CPU until it happens. The
  375.  * null event is special: it means "I don't want to block on an event, but let
  376.  * somebody else run for a while". It can also mean that the present process
  377.  * is terminating; in this case the wait never returns.
  378.  *
  379.  * Pwait() returns 0 if the event was signaled; otherwise it returns the
  380.  * arg in an alert() call. Pwait must not be called from interrupt level.
  381.  *
  382.  * Note that pwait can run with interrupts enabled even though it examines
  383.  * a few global variables that can be modified by psignal at interrupt time.
  384.  * These *seem* safe.
  385.  */
  386. void *
  387. pwait(void *event)
  388. {
  389.     struct proc *oldproc;
  390.     void *tmp;
  391.  
  392.     if(Curproc != NULLPROC) {    /* If process isn't terminating */
  393. #ifdef MDEBUG
  394.         chkstk();
  395. #endif
  396.         if(event == NULL) {
  397.             /* Special case; just give up the processor.
  398.              *
  399.              * Optimization: if nothing else is ready, just return.
  400.              */
  401.             if(Rdytab == NULLPROC) {
  402.                 return 0;
  403.             }
  404.         } else {
  405.             /* Post a wait for the specified event */
  406.             Curproc->event = event;
  407.             Curproc->state = WAITING;
  408.         }
  409.         addproc(Curproc);
  410.     }
  411.  
  412.     /* Look for a ready process and run it. If there are none,
  413.      * loop or halt until an interrupt makes something ready.
  414.      */
  415.     while(Rdytab == NULLPROC) {
  416.         /* Give system back to upper-level multitasker, if any.
  417.          * Note that this function enables interrupts internally
  418.          * to prevent deadlock, but it restores our state
  419.          * before returning.
  420.          */
  421.         giveup();
  422.     }
  423.  
  424.     /* Remove first entry from ready list */
  425.     oldproc = Curproc;
  426.     Curproc = Rdytab;
  427.     delproc(Curproc);
  428.  
  429.     /* Now do the context switch.
  430.      * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
  431.      *
  432.      * If the old process has gone away, simply load the new process's
  433.      * environment. Otherwise, save the current process's state. Then if
  434.      * this is still the old process, load the new environment. Since the
  435.      * new task will "think" it's returning from the setjmp() with a return
  436.      * value of 1, the comparison with 0 will bypass the longjmp(), which
  437.      * would otherwise cause an infinite loop.
  438.      */
  439. #ifdef    PROCTRACE
  440.     if(strcmp(oldproc->name,Curproc->name) != 0) {
  441.         tprintf("-> %s(%d)\n",Curproc->name,!!Curproc->i_state);
  442.     }
  443. #endif
  444.     /* Note use of comma operator to save old interrupt state only if
  445.      * oldproc is non-null
  446.      */
  447.     if(oldproc == NULLPROC
  448.      || (oldproc->i_state = istate(), setjmp(oldproc->env) == 0)) {
  449.         /* We're still running in the old task; load new task context.
  450.          * The interrupt state is restored here in case longjmp
  451.          * doesn't do it (e.g., systems other than Turbo-C).
  452.          */
  453.         restore(Curproc->i_state);
  454.         longjmp(Curproc->env,1);
  455.     }
  456.     /* At this point, we're running in the newly dispatched task */
  457.     tmp = Curproc->retval;
  458.     Curproc->retval = 0;
  459.  
  460.     /* Also restore the true interrupt state here, in case the longjmp
  461.      * DOES restore the interrupt state saved at the time of the setjmp().
  462.      * This is the case with Turbo-C's setjmp/longjmp.
  463.      */
  464.     restore(Curproc->i_state);
  465.     return tmp;
  466. }
  467.  
  468. /* Make ready the first 'n' processes waiting for a given event. The ready
  469.  * processes will see a return value of 0 from pwait().  Note that they don't
  470.  * actually get control until we explicitly give up the CPU ourselves through
  471.  * a pwait(). Psignal may be called from interrupt level. It returns the
  472.  * number of processes that were woken up.
  473.  */
  474. int
  475. psignal(
  476. void *event,    /* Event to signal */
  477. int n)            /* Max number of processes to wake up */
  478. {
  479.     struct proc *pp;
  480.     int i_state;
  481.     int cnt = 0;                /* 0 means "signal everybody waiting" */
  482.  
  483. #ifdef MDEBUG
  484.     chkstk();
  485. #endif
  486.     if(event == NULL) {
  487.         return 0;                /* Null events are invalid */
  488.     }
  489.     if(n == 0) {
  490.         n = 32766;
  491.     }
  492.     i_state = dirps();
  493.  
  494.     for(pp = Waittab; pp != NULLPROC; pp = pp->next) {
  495.         if(n == 0) {
  496.             break;
  497.         }
  498.         if(pp->event == event) {
  499. #ifdef    PROCTRACE
  500.             if(i_state) {
  501.                 tprintf("psignal(%lx,%u) wake %lx [%s]\n",
  502.                     ptol(event),n,ptol(pp),pp->name);
  503.             }
  504. #endif
  505.             delproc(pp);
  506.             pp->state &= ~WAITING;
  507.             pp->event = 0;
  508.             pp->retval = 0;
  509.             addproc(pp);
  510.             n--;
  511.             cnt++;
  512.         }
  513.     }
  514.     for(pp = Susptab; pp != NULLPROC; pp = pp->next) {
  515.         if(n == 0) {
  516.             break;
  517.         }
  518.         if(pp->event == event) {
  519. #ifdef    PROCTRACE
  520.             if(i_state) {
  521.                 tprintf("psignal(%lx,%u) wake %lx [%s]\n",
  522.                     ptol(event),n,ptol(pp),pp->name);
  523.             }
  524. #endif
  525.             delproc(pp);
  526.             pp->state &= ~WAITING;
  527.             pp->event = 0;
  528.             pp->retval = 0;
  529.             addproc(pp);
  530.             n--;
  531.             cnt++;
  532.         }
  533.     }
  534.     restore(i_state);
  535.     return cnt;
  536. }
  537.  
  538.